(* - - - - - FICHIER PRINCIPAL - - - - - *)

(* - - - INITIALISATION - - - *)

(* SDL *)
let sdl_init () =
  begin
    Sdl.init [`EVERYTHING];
    Sdlevent.enable_events Sdlevent.all_events_mask;
  end

(* - - - /\ - - - *)


(* - - - VARIABLES - - - *)
let is_image_loaded = ref false

let is_process_btn_clicked = ref false

let is_sample_btn_clicked = ref false

let image_name = ref "logo_symbiose.png"

let altitude_file = ref "altitude"

let obj_file = ref "obj.obj"

let base_surface = ref (Sdlloader.load_image !image_name)

let sample_space = ref 0

let altitude_space = ref 20

let color_list = ref []

let is_modelized = ref false

let modelize_option = ref "normal"

let alt_color_list = ref ObjList.cel_default

let filter_scale = ref 2



(* - - - FONCTION DE RECUPERATION DE LA COULEUR - - -*)

let fill_acl () =
  let altitude = !(altitude_file) in
  if Sys.file_exists altitude then
    begin
      let file = open_in altitude in
      let list = ref [] in
      try
	while true do
          let line = input_line file in
	  let current_color = ref "" in
          let current_altitude = ref "" in
	  let i = ref 0 in
          let is_color_done = ref false in
          while (!i < String.length line) do
            if not (!is_color_done) then
              if(line.[!i] = ' ')then
		is_color_done := true
              else
                current_color :=
		  !current_color^(Char.escaped(line.[!i]))
            else
              current_altitude :=
		!current_altitude^(Char.escaped(line.[!i]));
            i := !i + 1;
          done;
	  i := 1;
	  let r = ref "" in
          let g = ref "" in
          let b = ref "" in
	  let current = ref 0 in
	  while (!i < String.length !current_color - 1) do
	    if (!current = 0) then
	      if (!current_color.[!i] = ',') then
		current := 1
	      else
		r := !r^(Char.escaped(line.[!i]))
	    else
	      if (!current = 1) then
		if (!current_color.[!i] = ',') then
                  current := 2
		else
                  g := !g^(Char.escaped(line.[!i]))
	      else
		if not (!current_color.[!i] = ')') then
                  b := !b^(Char.escaped(line.[!i]));
	    i := !i + 1
	  done;
	  list := (int_of_string !current_altitude,
		   ((float_of_string !r) /. 255.,
		    (float_of_string !g) /. 255.,
		    (float_of_string !b) /. 255.))::!list
        done;
	!list
      with
          End_of_file -> close_in file;
            !list  
    end
  else
    []

(* Liste reference de couplet de reference label et champ *)
(*let altitude_field_list = ref []*)

(* - - - /\ - - - *)


(* - - - FENETRE PRINCIPALE - - - *)
let main_window =
  let window = GWindow.window
    ~title:"Symbiose - Dimensionize"
    ~resizable:true
    ~border_width:20
    ~width:1024
    ~height:768 () in
    ignore(window#connect#destroy
             (fun () ->
		(if (Sys.file_exists
                       ((!image_name)^".temp"))
                 then
                   Sys.remove ((!image_name)^".temp"));
		(if (Sys.file_exists
                       ((!image_name)^".temp2")) then
                   Sys.remove ((!image_name)^".temp2")); 
		(if (Sys.file_exists
                       ((!image_name)^".temp3")) then
                   Sys.remove ((!image_name)^".temp3"));
		GMain.quit ()
             ));
    window

(* - - - /\ - - - *)


(* - - - BOXES PRINCIPALES - - - *)
(* - - Boite principale - - *)
let main_hbox = GPack.hbox
  ~packing:main_window#add ()

(* - - Panneau à onglet - - *)
let main_panel =
  let panel = GPack.notebook
    ~packing:main_hbox#add () in
    panel

(* - - - /\ - - - *)


(* - - - FONCTIONS GENERALES - - - *)
let convert_file = function
  | Some x -> x
  | _ -> is_image_loaded := false;
      is_process_btn_clicked := false;
      is_sample_btn_clicked := false;
      "logo_symbiose.png"

let field_convert = function
  | "" -> 0
  | x -> int_of_string x

let save_image filename =
  if Sys.file_exists
    ((!image_name)^".temp3")
  then
    Sys.rename ((!image_name)^".temp3") filename
  else if Sys.file_exists
      ((!image_name)^".temp2")
  then
    Sys.rename ((!image_name)^".temp2") filename
  else
    if Sys.file_exists
      ((!image_name)^".temp")
    then
      Sys.rename ((!image_name)^".temp") filename
	
let get_triplet_string = function
  | (x,y,z) -> "("^(string_of_int x)^","
      ^(string_of_int y)^","^(string_of_int z)^")"

let rec get_string_list i = function
  | [] -> failwith "Empty list or index out of bound"
  | e::l -> if i = 0 then
      get_triplet_string e
    else
      get_string_list (i - 1) l

let save_altitude filename =
  ObjList.write_alt filename !alt_color_list;
  altitude_file := filename
  (*open_alt#filename = filename*)

let save_obj filename =
  WriteObj.objectize !base_surface !sample_space filename !altitude_file;
  obj_file := filename
  (*open_obj#filename = filename*)

let generic_save_button stock name condition event box func =
  let dialog = GWindow.file_chooser_dialog
    ~action:`SAVE
    ~parent:main_window
    ~position:`CENTER_ON_PARENT
    ~destroy_with_parent:true () in
  let button = GButton.button
    ~label:name
    ~packing:box#add () in
    dialog#add_button_stock `CANCEL `CANCEL;
    dialog#add_select_button_stock stock event;
    ignore(button#connect#clicked
	     (fun () -> if condition then
		(if dialog#run () = `SAVE then
		   Gaux.may func dialog#filename;
		 dialog#misc#hide ());
	     ));
    button

let rec destroy_list_element = function
  | [] -> ()
  | (b,lb,f)::l -> (!b)#destroy; (!lb)#destroy; (!f)#destroy;
      destroy_list_element l

let clear_list l =
  l := []

(* - - - /\ - - - *)


(* - - - ELEMENTS DE L'INTERFACE - - - *)
(* - - Emplacement de l'image - - *)
let image_hbox =
  let vbox = GPack.vbox () in
  let label = GMisc.label
    ~text:"Image preview" () in
  let tab = main_panel#insert_page
    ~tab_label:label#coerce vbox#coerce in
  let box = GPack.hbox
    ~packing:vbox#add () in
  ignore(tab);
  box


let main_image =
  let image = GMisc.image
    ~file:"logo_symbiose.png"
    ~packing:image_hbox#add () in
    image


(* - - Emplacement du module 3D - - *)
let main_3Ddisplay =
  let vbox = GPack.vbox () in
  let label = GMisc.label
    ~text:"3D preview" () in
  let tab = main_panel#insert_page
    ~tab_label:label#coerce vbox#coerce in
  let box = GPack.hbox
    ~packing:vbox#add () in
    ignore(tab);
    box


(* - - Box et 'champs' de l'onglet options - - *)
let opt_hbox =
  let vbox = GPack.vbox () in
  let label = GMisc.label
    ~text:"Options" () in
  let tab = main_panel#insert_page
    ~tab_label:label#coerce vbox#coerce in
  let hbox = GPack.hbox
    ~packing:vbox#add () in
    ignore(tab);
    hbox


(* - Partie Gauche - *)
let opt_lvbox = GPack.vbox
  ~border_width:10
  ~packing:opt_hbox#add ()

(* Champs de l'espace du quadrillage *)
let field_hbox = GPack.hbox
  ~packing:opt_lvbox#add ()

let field_label =
  let label = GMisc.label
    ~text:"Image grid size"
    ~packing:field_hbox#add () in
    label

let field_box =
  let field = GEdit.entry
    ~text:"20"
    ~packing:field_hbox#add () in
    sample_space := (int_of_string
		       field#text);
    ignore(field#connect#changed
      (fun () ->
	 sample_space := (field_convert field#text)
      ));
    field

(* Boutons des modes 3D *)
let option_button =
  let box = GPack.vbox
    ~packing:opt_lvbox#add () in
  let normal = GButton.radio_button ~label:"Normal"
    ~active:true ~packing:box#add () in
  let wireframe = GButton.radio_button ~group:normal#group ~label:"Wireframe"
    ~packing:box#add () in
  let points_field = GButton.radio_button ~group:normal#group ~label:"Points Field"
    ~packing:box#add () in
  ignore(normal#connect#clicked (fun () -> modelize_option := "normal"));
  ignore(wireframe#connect#clicked (fun () -> modelize_option := "wireframe"));
  ignore(points_field#connect#clicked (fun () -> modelize_option := "pointsfield"));
  box

(* - Partie Droite - *)
let opt_rvbox = GPack.vbox
  ~border_width:10
  ~packing:opt_hbox#add ()

let opt_top_rvbox = GPack.vbox
  ~packing:opt_rvbox#add ()

let opt_bot_rvbox = GPack.vbox
  ~packing:opt_rvbox#add ()

(* Boutons d'enregistrement des altitudes et champ dans opt_rvbox *)
(* Champ pour recuperer la valeur d'espace entre les altitudes *)
let altitude_field =
  let field = GEdit.entry
    ~text:"20"
    ~packing:opt_bot_rvbox#add () in
    altitude_space := (int_of_string
			 field#text);
    ignore(field#connect#changed
	     (fun () ->
		let i = ref 0 in
		  while !i < (ObjList.sizeofcel !alt_color_list) do
		    ObjList.change_entry_content !alt_color_list !i
		      (string_of_int (!i * (field_convert field#text)));
		    i := !i + 1
		  done;
			
	     ));
    field

let savealtitude_button =
  generic_save_button `SAVE "Save altitudes" true `SAVE opt_bot_rvbox save_altitude

(* Liste des champs de couleurs d'altitudes *)
let alt_color_field_create () =
  ObjList.delete !alt_color_list opt_top_rvbox;
  let hbox = GPack.hbox () in
  let color = GMisc.label
    ~text:(get_string_list 0 !color_list) () in
  let entry = GEdit.entry
    ~text:"0" () in
  let i = ref 1 in
    alt_color_list := ObjList.create (List.length !color_list)
      hbox color (get_string_list 0 !color_list) entry;
    while !i < (List.length !color_list) do
      let hbox = GPack.hbox () in
      let color = GMisc.label
	~text:(get_string_list !i !color_list) () in
      let entry = GEdit.entry
	~text:(string_of_int (!i * 10)) () in
	ObjList.insert !alt_color_list hbox color
	  (get_string_list !i !color_list) entry;
	i := !i + 1
    done;
    ObjList.generate !alt_color_list opt_top_rvbox


(* - - Box et 'labels' des commandes - - *)
(*let controls_hbox =
  let vbox = GPack.vbox () in
  let label = GMisc.label
    ~text:"Controls" () in
  let tab = main_panel#insert_page
    ~tab_label:label#coerce vbox#coerce in
  let hbox = GPack.hbox
    ~packing:vbox#add () in
    ignore(tab);
    hbox*)


(* - - BOUTONS - - *)
(* - - Boite a boutons - - *)
let image_bb = GPack.button_box `VERTICAL
  ~layout:`SPREAD
  ~border_width:20
  ~packing:(image_hbox#pack ~expand:false) ()

let troisd_bb = GPack.button_box `VERTICAL
  ~layout:`SPREAD
  ~border_width:20
  ~packing:(main_3Ddisplay#pack ~expand:false) ()

let option_bb = GPack.button_box `VERTICAL
  ~layout:`SPREAD
  ~border_width:20
  ~packing:(opt_hbox#pack ~expand:false) ()


let image_filter = GFile.filter
  ~name:"Image files"
  ~patterns:["*.jpg"; "*.bmp"; "*.png"; "*.tif"] ()


let browse_button =
  let button = GFile.chooser_button
    ~action:`OPEN
    ~packing:image_bb#add () in
    ignore(button#connect#selection_changed
      ~callback:(fun _ ->
		   is_image_loaded
		     := true;
		   is_process_btn_clicked
		     := false;
		   is_sample_btn_clicked
		     := false;
		   (if (Sys.file_exists
                         ((!image_name)^".temp"))
                    then
                     Sys.remove
                       ((!image_name)^".temp"));
		   (if (Sys.file_exists
			  ((!image_name)^".temp2"))
		    then
		      Sys.remove
			((!image_name)^".temp2"));
		   (if (Sys.file_exists
			  ((!image_name)^".temp3"))
		    then
		      Sys.remove
			((!image_name)^".temp3"));
		   image_name := (convert_file
				    button#filename);
		   base_surface := Sdlloader.load_image !image_name;
		   main_image#set_file !image_name
		));
    button#set_filter image_filter;
    button


(* Sample de l'image et actualisation *)
let filter_button =
  let button = GButton.button
    ~label:"Filter image"
    ~packing:image_bb#add () in
  ignore(button#connect#clicked
           (fun () -> if !is_image_loaded &&
               (not !is_process_btn_clicked) then
               begin
                 let file = Image.filter_image !image_name !filter_scale in
                 main_image#set_file file
	       end
           ));
  button


(* Traitement de l'image et actualisation *)
let process_button =
  let button = GButton.button
    ~label:"Process image"
    ~packing:image_bb#add () in
    ignore(button#connect#clicked
      (fun () -> if !is_image_loaded &&
	 (not !is_process_btn_clicked) then
	   begin
	     is_process_btn_clicked
	       := true;
	     let file = Image.process_image !image_name color_list in
	       main_image#set_file file;
	       alt_color_field_create ()
	   end
      ));
    button


(* Sample de l'image et actualisation *)
let sample_button =
  let button = GButton.button
    ~label:"Sample image"
    ~packing:image_bb#add () in
    ignore(button#connect#clicked
      (fun () -> if !is_image_loaded &&
	 !is_process_btn_clicked then
	   begin
	     is_sample_btn_clicked
	       := true;
	     let file = Image.sample_image !image_name !sample_space in
	       main_image#set_file file
	   end
      ));
    button


let saveimage_button = generic_save_button `SAVE
  "Save processed image" true `SAVE image_bb save_image

let saveobj_button =
  let dialog = GWindow.file_chooser_dialog
    ~action:`SAVE
    ~parent:main_window
    ~position:`CENTER_ON_PARENT
    ~destroy_with_parent:true () in
  let button = GButton.button
    ~label:"Save .obj"
    ~packing:option_bb#add () in
    dialog#add_button_stock `CANCEL `CANCEL;
    dialog#add_select_button_stock `SAVE `SAVE;
    ignore(button#connect#clicked
             (fun () -> if !is_sample_btn_clicked then
		(if dialog#run () = `SAVE then
                   Gaux.may save_obj dialog#filename;
                 dialog#misc#hide ());
             ));
    button

let modelize_button =
  let button = GButton.button
    ~label:"Modelize"
    ~packing:troisd_bb#add () in
  ignore(button#connect#clicked
    (fun () ->
      if not !is_modelized then
        begin
          is_modelized := true;
          main_panel#goto_page 1;
          let alt_list = fill_acl () in
          let a = 
            Troisd.createGLArea "Modelize" alt_list main_window !obj_file 640 480 16 false !modelize_option main_3Ddisplay in
            ignore(a)
        end
      else
        begin
          let (tmp_vertices, tmp_faces) = WriteObj.read_obj !obj_file in
          Troisd.alt_list := fill_acl ();
          Troisd.vertices := tmp_vertices;
          Troisd.faces := tmp_faces;
          Troisd.display_option := !modelize_option;
          (*alt_color_field_create ();*)
        end
    ));
  button


let open_alt =
  let button = GFile.chooser_button
    ~action:`OPEN
    ~packing:option_bb#add () in
    ignore(button#connect#selection_changed
	     ~callback:(fun _ ->
                          altitude_file := (convert_file
					   button#filename);
		       ));
    button

let open_obj =
  let button = GFile.chooser_button
    ~action:`OPEN
    ~packing:troisd_bb#add () in
    ignore(button#connect#selection_changed
             ~callback:(fun _ ->
                          obj_file := (convert_file
                                          button#filename);
                       ));
    button


let quit_button =
  let button = GButton.button
    ~label:"Quit"
    ~packing:image_bb#add () in
    ignore(button#connect#clicked
      (fun () ->
	 (if (Sys.file_exists
		((!image_name)^".temp"))
	  then
	    Sys.remove ((!image_name)^".temp"));
	 (if (Sys.file_exists
		((!image_name)^".temp2")) then
	    Sys.remove ((!image_name)^".temp2"));
	 (if (Sys.file_exists
		((!image_name)^".temp3")) then
             Sys.remove ((!image_name)^".temp3")); 
	 GMain.quit ()
      ));
    button

(* - - - FONCTION PRINCIPALE ET POINT D'ENTREE - - - *)
let main () =
  sdl_init ();
  main_window#show ();
  GMain.main ()

let _ = main ()
